package com.luty.rpc.server;

import com.luty.rpc.common.bean.RpcRequest;
import com.luty.rpc.common.bean.RpcResponse;
import com.luty.rpc.common.util.StringUtil;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;

/**
 * Created by Luty on 2017/6/19.
 */
public class RpcServerHandle extends SimpleChannelInboundHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(RpcServerHandle.class);

    private final Map<String, Object> handlerMap;

    public RpcServerHandle(Map<String, Object> handlerMap){
        this.handlerMap = handlerMap;
    }

    private Object handle(RpcRequest rpcRequest) throws InvocationTargetException {
        //获取服务对象
        String serviceName = rpcRequest.getInterfaceName();
        String serviceVersion = rpcRequest.getServiceVersion();

        if(StringUtil.isNotEmpty(serviceVersion)){
            serviceName += "-" + serviceVersion;
        }

        Object serviceBean = handlerMap.get(serviceName);
        if(serviceBean == null){
            throw new RuntimeException(String.format("can not find service bean by key: %s", serviceName));
        }
        //获取反射所需要的参数
        Class<?> serviceClass = serviceBean.getClass();
        String methodName = rpcRequest.getMethodName();

        Class<?>[] parameterTypes  = rpcRequest.getParameterTypes();
        Object[] parameters = rpcRequest.getParamters();

        FastClass serviceFastClass = FastClass.create(serviceClass);
        FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, parameterTypes);

        return serviceFastMethod.invoke(serviceBean,parameters);
    }

    @Override
    protected void messageReceived(ChannelHandlerContext context, Object o) throws Exception {
        RpcResponse response = new RpcResponse();
        RpcRequest request = (RpcRequest) o;
        response.setRequestId(request.getRequestId());
        try {
            Object result = handle(request);
            response.setResult(result);
        }catch (Exception e){
            LOGGER.error("handle result failure", e);
            response.setException(e);
        }

        context.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }
}
